#include "threadpool.h"
#include <thread>
#include <functional>
#include <iostream>

const int TASK_QUE_MAX = 4;
const int THREAD_SIZE_MAX = 10;
const int THREAD_IDLE_MAX_TIME = 60; // 单位：秒

ThreadPool::ThreadPool()
    : init_threadpool_size_(0), task_que_size_(0), idle_threads_(0), cur_thread_size_(0), max_thread_size_(THREAD_SIZE_MAX), task_que_max_(TASK_QUE_MAX), is_start_(false), is_runing_(true)
{
}
ThreadPool::~ThreadPool()
{
    is_runing_ = false;

    // 回收线程池内的线程资源
    // 一种是空闲线程，一种是正在执行任务的线程
    // 当线程池生命周期结束，线程跳出线程函数，线程池删除掉该线程，当线程池的size=0，彻底销毁完成。
    std::unique_lock<std::mutex> lock(task_que_mtx_);
    not_empty_.notify_all();
    exit_.wait(lock, [&]() -> bool
               { return threads_.size() == 0; });
}

// 设置线程池模式
void ThreadPool::SetThreadPoolModel(ThreadPoolModel threadpool_model)
{
    if (is_start_)
    {
        std::cerr << "can`t set thread pool model because the thread pool is start !" << std::endl;
        return;
    }
    this->thread_pool_model = threadpool_model;
}
// 设置线程池个数上限
void ThreadPool::SetThreadPoolThreadMax(size_t max_size)
{
    if (is_start_)
    {
        std::cerr << "can`t set threads max because the thread pool is start !" << std::endl;
        return;
    }
    this->max_thread_size_ = max_size;
}
// 设置任务队列上限
void ThreadPool::SetTaskQueMaxThreashhold(size_t task_que_max)
{
    if (is_start_)
    {
        std::cerr << "can`t set task que max because the thread pool is start !" << std::endl;
        return;
    }
    this->task_que_max_ = task_que_max;
}
// 往任务队列里插入任务
Result ThreadPool::SubmitTask(std::shared_ptr<Task> task)
{
    if (is_start_)
    {
        // 获取锁
        std::unique_lock<std::mutex> lock(this->task_que_mtx_);
        // 检查任务队列能否插入，如果不能等待1s，超时即表示本次插入失败。
        auto status = not_full_.wait_for(lock, std::chrono::seconds(1), [&]() -> bool
                                         { return task_que_.size() < task_que_max_; });
        if (!status)
        {
            std::cerr << "submit task fail, plase wait ." << std::endl;
            return Result(task, false);
        }
        // 任务队列插入任务
        task_que_.emplace(task);
        task_que_size_++;

        // 根据任务数量增减线程池内线程个数
        if (task_que_size_ > idle_threads_ && cur_thread_size_ < max_thread_size_ && thread_pool_model == ThreadPoolModel::MODEL_CACHEED)
        {
            std::cout << "create new thread" << std::endl;
            // 创建线程对象的时候，把线程函数给到新创建的线程对象
            auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::ThreadFunc, this, std::placeholders::_1));
            int thread_id = ptr->getThreadId();
            // 直接传递ptr,会在容器内调用拷贝此元素，所以这里用所有权转移进容器内。
            this->threads_.emplace(thread_id, std::move(ptr));
            this->threads_[thread_id]->start();
            // 线程参数改变
            this->idle_threads_++;
            this->cur_thread_size_++;
        }

        // 通知任务队列非空
        not_empty_.notify_all();

        // 返回任务的执行结果。
        return Result(task);
    }
    else
    {
        std::cerr << "can`t submit task because the thread pool is not start !" << std::endl;
        return Result(task, false);
    }
}
// 开启线程池
void ThreadPool::start(size_t init_threadpool_size)
{
    // 设置线程池初始线程个数
    this->init_threadpool_size_ = init_threadpool_size;
    this->cur_thread_size_ = init_threadpool_size;

    for (size_t i = 0; i < init_threadpool_size; i++)
    {
        // 创建线程对象的时候，把线程函数给到新创建的线程对象
        auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::ThreadFunc, this, std::placeholders::_1));
        int thread_id = ptr->getThreadId();
        // 直接传递ptr,会在容器内调用拷贝此元素，所以这里用所有权转移进容器内。
        this->threads_.emplace(thread_id, std::move(ptr));
    }

    for (size_t i = 0; i < init_threadpool_size; i++)
    {
        this->threads_[i]->start();
        this->idle_threads_++;
    }

    is_start_ = true;
}

// 从任务队列中拿任务进行处理。
void ThreadPool::ThreadFunc(int thread_id)
{
    auto last_time = std::chrono::high_resolution_clock().now();
    // 一直处理直到将任务队列搬空
    while (true)
    {
        std::shared_ptr<Task> task_ptr;
        {
            // 获取锁
            std::unique_lock<std::mutex> lock(task_que_mtx_);
            std::cout << "id is : " << std::this_thread::get_id() << "尝试获取任务" << std::endl;
            // 任务列表有任务才会执行
            // 任务列表没有任务的时候，1、就要等待，2、就要在cached模式下，销毁一些空闲线程。
            while (task_que_.size() == 0)
            {
                if (!is_runing_)
                {
                    threads_.erase(thread_id);
                    std::cout << "this thread id is " << std::this_thread::get_id() << "exit !" << std::endl;
                    exit_.notify_all();
                    // 退出线程函数，线程销毁。
                    return;
                }
                // 判断线程池模式
                if (this->thread_pool_model == ThreadPoolModel::MODEL_CACHEED)
                {
                    // 设置1秒钟检测一次，超过的线程就销毁。
                    auto thread_status = not_empty_.wait_for(lock, std::chrono::seconds(1));
                    if (thread_status == std::cv_status::timeout)
                    {
                        auto now_time = std::chrono::high_resolution_clock().now();
                        auto dur_time = std::chrono::duration_cast<std::chrono::seconds>(now_time - last_time).count();
                        if (dur_time > THREAD_IDLE_MAX_TIME && cur_thread_size_ > init_threadpool_size_)
                        {
                            // 进行线程的销毁。
                            // 线程池内该线程的剔除。
                            threads_.erase(thread_id);

                            // 线程池相关成员变量的变化。
                            this->cur_thread_size_--;
                            this->idle_threads_--;
                            std::cout << "this thread id is " << std::this_thread::get_id() << "exit !" << std::endl;
                            // 退出线程函数，线程销毁。
                            return;
                        }
                    }
                }
                else
                {
                    // 等待非空条件.刚开始创建的所有线程，都阻塞在这里等待任务队列里面有任务。
                    not_empty_.wait(lock);
                }

                // if (!is_runing_)
                // {
                //     threads_.erase(thread_id);

                //     std::cout << "this thread id is " << std::this_thread::get_id() << "exit !" << std::endl;
                //     exit_.notify_all();
                //     // 退出线程函数，线程销毁。
                //     return;
                // }
            }

            // 空闲线程减一
            this->idle_threads_--;
            std::cout << "id is : " << std::this_thread::get_id() << "获取任务成功" << std::endl;
            // 从任务队列中取出任务
            task_ptr = task_que_.front();
            task_que_.pop();
            task_que_size_--;

            // 如果非空，通知其它线程也可以干活了
            if (task_que_size_ != 0)
            {
                not_empty_.notify_all();
            }
            // 通知非满条件
            not_full_.notify_all();
        } // 锁只需要加在操作任务队列，不能执行任务的时候还加锁。切记，锁应该锁住什么区域。

        // 执行任务
        if (task_ptr != nullptr)
        {
            task_ptr->exec();
        }
        // 执行任务完，空闲线程+1
        this->idle_threads_++;
        last_time = std::chrono::high_resolution_clock().now();
    }
}

/////////////                   线程类成员函数实现
Thread::Thread(Func func)
    : func_(func), thread_id_(thread_count_num_)
{
    thread_count_num_++;
}
Thread::~Thread()
{
}
int Thread::thread_count_num_ = 0;

void Thread::start()
{
    std::thread t(this->func_, thread_id_);
    t.detach();
}
int Thread::getThreadId() const
{
    return thread_id_;
}
/////////////                   Task方法实现
void Task::setResult(Result *res)
{
    result_ = res;
}
void Task::exec()
{
    result_->setAny(run()); // 动态执行放在了这里，并且这里返回了线程结果
}
////////////                    Result方法实现
Result::Result(std::shared_ptr<Task> task, bool is_value)
    : task_(task), is_value_(is_value)
{
    task_->setResult(this);
}
void Result::setAny(Any any)
{
    any_ = std::move(any);
    sempth_.post();
}

Any Result::get()
{
    if (is_value_ == false)
    {
        return "";
    }
    sempth_.wait(); // 任务如果没有执行完，就会阻塞在这里等待任务执行完，等待any有结果。
    return std::move(any_);
}